#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
#include <ctime>


using namespace cv;
using namespace std;


/*
			绘制直线：
			line()
				void cv::line(InputOutputArray img,Point pt1,Point pt2,const Scalar& color,int thickness = 1,int lineType = LINE_8,int shift = 0);
			绘制圆形：
			circle()
				void cv::circle(InputOutputArray img,Point center,int radius,const Scalar& color,int thickness = 1,int lineType = LINE_8,int shift = 0)
			绘制椭圆形：
			ellipse()
				void cv::ellipse(InputOutputArray img,Point center,Size axes,double angle,double startAngle,double endAngle,const Scalar& color,int thickness = 1,int lineType = LINE_8,int shift = 0)
			绘制矩形：
			rectangle()
				void cv::rectangle(InputOutputArray img,Point pt1,Point pt2,const Scalar& color,int thickness = 1,int lineType = LINE_8,int shift = 0)
			绘制多边形：
			polylines()
				简单版本：
				void polylines(InputOutputArray img, InputArrayOfArrays pts, bool isClosed, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0 );
				复杂版本：
				void polylines(InputOutputArray img, const Point* const* pts, const int* npts, int ncontours, bool isClosed, const Scalar & color, int thickness = 1, int lineType = LINE_8, int shift = 0);
			绘制填充多边形：
			fillPoly()
				简单版本：
				void fillPoly(InputOutputArray img, InputArrayOfArrays pts, const Scalar& color, int lineType = LINE_8, int shift = 0, Point offset = Point() );
				复杂版本：
				void cv::fillPoly(InputOutputArray img,const Point** pts,const int* npts,int ncontours,const Scalar& color,int lineType = LINE_8,int shift = 0,Point offset = Point());
			绘制文字：
			putText()
				void cv::putText(InputOutputArray img,const String& text,Point org,int fontFace,double fontSize,Scalar color,int thickness = 1,int lineType = LINE_8,bool bottomLeftOrigin = fasle);


*/


class Draw_graph
{
private:
	Mat img;

public:
	Draw_graph(const string& filename)
		:img(imread(filename))
	{ }
	Draw_graph()
		:img(Mat(200, 200,CV_8UC3))
	{ }
	void Show(const string& type = "img1")
	{
		imshow(type, img);
		waitKey();
	}

	void draw_line(int s_x, int s_y, int e_x, int e_y)
	{
		/*
			绘制直线：
			line()
				void cv::line(InputOutputArray img,Point pt1,Point pt2,const Scalar& color,int thickness = 1,int lineType = LINE_8,int shift = 0);
					img:绘制圆形的图像
					pt1:直线起始点在图像中的坐标
					pt2:直线终点在图像中的坐标
					color:圆形的颜色，用三通道标识
					thickness:轮廓的宽度
					lineType:边界的类型，可以取值为FILLED,LINE_4,LINE_8 和 LINE_AA
					shift:中心坐标和半径数值中的小数位数
		*/

		line(img, Point(s_x, s_y), Point(e_x, e_y), Scalar(0, 0, 255), 2, LINE_AA);

	}
	void draw_circle(int x = 100, int y = 100, int r = 10)
	{
		/*	
			绘制圆形：
			circle()
				void cv::circle(InputOutputArray img,Point center,int radius,const Scalar& color,int thickness = 1,int lineType = LINE_8,int shift = 0)
					img:绘制圆形的图像
					center:圆形的中心位置
					color:圆形的颜色，用三通道表示
					thickness:轮廓的宽度，如果设置成-1，就表示是实心圆
					radius:圆形的半径长度，单位为像素
					lineType:边界的类型，可以取值为FILLED,LINE_4,LINE_8 和 LINE_AA
		*/

		circle(img, Point(x, y), r, Scalar(255, 0, 0), -1, FILLED);				//实心圆
		circle(img, Point(x, y), r + 4, Scalar(255, 0, 0), 2, FILLED);			//空心圆
	}
	void draw_ellipse(int x = 200, int y = 200, Size size = { 19,35 })
	{
		/*
			绘制椭圆形：
			ellipse()
				void cv::ellipse(InputOutputArray img,Point center,Size axes,double angle,double startAngle,double endAngle,const Scalar& color,int thickness = 1,int lineType = LINE_8,int shift = 0)
					img:绘制圆形的图像
					center:圆形的中心位置
					axes:椭圆主轴大小的一半
					angle:椭圆旋转的角度，单位为度
					startAngle:椭圆弧起始的角度，单位为度
					endAngle:椭圆弧终止的角度，单位为度
					color:圆形的颜色，用三通道表示
					thickness:轮廓的宽度，如果设置成-1，就表示是实心圆
					radius:圆形的半径长度，单位为像素
		*/

		ellipse(img,Point(x,y),size,90,0,360,Scalar(0,255,0),1);	//360度的范围中旋转90度的空心椭圆
		ellipse(img,Point(x,y),size,180,0,360,Scalar(0,255,0),-1);//360度的范围中旋转90度的实心椭圆

	}
	void draw_rectangle(int x = 100, int y = 100, int w = 40, int h = 46)
	{
		/*
			绘制矩形：
			rectangle()
				void cv::rectangle(InputOutputArray img,Point pt1,Point pt2,const Scalar& color,int thickness = 1,int lineType = LINE_8,int shift = 0)
					img:绘制矩形的图像
					color:矩形的颜色，用三通道标识
					thickness:轮廓的宽度，如果设置成-1，就表示是实心矩形
					lineType:边界的类型，可以取值为FILLED,LINE_4,LINE_8 和 LINE_AA
					shift:中心坐标和半径数值中的小数位数
		*/

		rectangle(img, Rect(x, y, w, h), Scalar(0, 255, 0), -1);

	}
	void draw_polygon(int img_size_w = 300,int img_size_h = 648)
	{
		/*
			绘制多边形：
			polylines()
				简单版本：
				void polylines(InputOutputArray img, InputArrayOfArrays pts, bool isClosed, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0 );
					img:绘制矩形的图像
					pts:点坐标的集合
					isClosed:多边形是否闭合
					color:矩形的颜色，用三通道标识
					thickness:轮廓的宽度，				注意，这个版本是不能使用-1即填充多边形的，会产生中断
					lineType:边界的类型，可以取值为FILLED,LINE_4,LINE_8 和 LINE_AA
					shift:中心坐标和半径数值中的小数位数
				复杂版本：
				void polylines(InputOutputArray img, const Point* const* pts, const int* npts, int ncontours, bool isClosed, const Scalar & color, int thickness = 1, int lineType = LINE_8, int shift = 0);
					img:绘制矩形的图像
					pts:点坐标的集合
					npts:点坐标的个数
					ncontours:待绘制的折线数
					isClosed:多边形是否闭合
					color:矩形的颜色，用三通道标识
					thickness:轮廓的宽度，				注意，这个版本是不能使用-1即填充多边形的，会产生中断
					lineType:边界的类型，可以取值为FILLED,LINE_4,LINE_8 和 LINE_AA
					shift:中心坐标和半径数值中的小数位数

			绘制填充多边形:
			fillPoly()
				简单版本：
				void fillPoly(InputOutputArray img, InputArrayOfArrays pts, const Scalar& color, int lineType = LINE_8, int shift = 0, Point offset = Point() );
					img:绘制多边形的图像
					pts:多边形顶点数组，可以存放多个多边形的订单坐标的数组
					color:矩形的颜色，用三通道标识
					lineType:边界的类型，可以取值为FILLED,LINE_4,LINE_8 和 LINE_AA
					shift:中心坐标和半径数值中的小数位数
					offset:所有顶点的可选偏移
				复杂版本:
				void cv::fillPoly(InputOutputArray img,const Point** pts,const int* npts,int ncontours,const Scalar& color,int lineType = LINE_8,int shift = 0,Point offset = Point())
					img:绘制多边形的图像
					pts:多边形顶点数组，可以存放多个多边形的订单坐标的数组
					npts:每个多边形顶点的数组中的顶点个数
					ncontours:绘制多边形的个数
					color:矩形的颜色，用三通道标识
					lineType:边界的类型，可以取值为FILLED,LINE_4,LINE_8 和 LINE_AA
					shift:中心坐标和半径数值中的小数位数
					offset:所有顶点的可选偏移
		*/

		vector<Point> pixel;

		//随机生成五个随机数，作为多边形的坐标：
		for (int i = 0; i < 5; i++)
		{
			pixel.push_back(Point(rand() % img_size_w, rand() % img_size_h));
		}

#if 0
		//简单版本：
		polylines(img, pixel, true, Scalar(0, 0, 255), 1);
		fillPoly(img, pixel, Scalar(255, 0, 0), 1);
#else
		//复杂版本:
		int size = 5;
		auto p = pixel.data();
		polylines(img, &p, &size, 1, true, Scalar(0, 255, 0), 1);
		const Point** pts = const_cast<const Point**>(&p);
		fillPoly(img, pts, &size, 1, Scalar(255, 0, 255));
#endif

	}
	void  draw_puttext(const String& text = "opencv test draw puttext", int x = 40, int y = 500, int fontFace = FONT_HERSHEY_PLAIN)
	{
		/*
			绘制文字：
			putText()
				void cv::putText(InputOutputArray img,const String& text,Point org,int fontFace,double fontSize,Scalar color,int thickness = 1,int lineType = LINE_8,bool bottomLeftOrigin = fasle)
					img:绘制文字的图像
					text:输出到图像中的文字，目前Opencv4只支持英文
					org:图像中文字字符串的左下角像素坐标
					fontFace:字体类型的选择标志
						FONT_HERSHEY_SIMPLEX：普通大小的无衬线字体。
						FONT_HERSHEY_PLAIN：小号的无衬线字体。
						FONT_HERSHEY_DUPLEX：普通大小的无衬线字体，比FONT_HERSHEY_SIMPLEX更复杂。
						FONT_HERSHEY_COMPLEX：较大的有衬线字体。
						FONT_HERSHEY_TRIPLEX：较大的有衬线字体，比FONT_HERSHEY_COMPLEX更复杂。
						FONT_HERSHEY_COMPLEX_SMALL：小号的有衬线字体。
						FONT_HERSHEY_SCRIPT_SIMPLEX：手写风格的无衬线字体。
						FONT_HERSHEY_SCRIPT_COMPLEX：手写风格的有衬线字体
					fontSize:字体的大小
					color:矩形的颜色，用三通道标识
					thickness:轮廓的宽度
					lineType:边界的类型，可以取值为FILLED,LINE_4,LINE_8 和 LINE_AA
					bottomLeftOrigin:图像数据原点的位置，默认为左上角，如果参数改为true，则原点为左下角,即倒立着的文本
		*/

		putText(img, text, Point(x, y), fontFace, 1.0, Scalar(255, 255, 255), 2, LINE_AA, false);

	}
};



int main()
{
	//生成随机函数种子:
	srand((unsigned int)time(nullptr));


	unique_ptr<Draw_graph> dgrap(new Draw_graph("mm.jpg"));
	dgrap->draw_line(0, 0, 300, 648);
	dgrap->draw_circle(150,324);
	dgrap->draw_rectangle();
	dgrap->draw_ellipse();
	dgrap->draw_puttext();
	dgrap->draw_polygon();

	dgrap->Show();

	return 0;
}
